import aiohttp
import asyncio
from pathlib import Path
from datetime import datetime
import re
import threading
from concurrent.futures import Future
from aiohttp import FormData

class AsyncUploadService:
    def __init__(self):
        self.time_format = "%Y%m%d_%H%M%S"
        self.max_retries = 3
        self.retry_delay = 2
        self._loop = None
        self._background_thread = None
        self._setup_background_loop()

    def _setup_background_loop(self):
        """初始化后台事件循环"""
        self._loop = asyncio.new_event_loop()
        self._background_thread = threading.Thread(
            target=self._start_background_loop,
            args=(self._loop,),
            daemon=True
        )
        self._background_thread.start()

    @staticmethod
    def _start_background_loop(loop: asyncio.AbstractEventLoop) -> None:
        """后台线程运行事件循环"""
        asyncio.set_event_loop(loop)
        loop.run_forever()

    def upload_images(self, source_dir: str, api_url: str, 
                    camera_name: str, video_name: str, algorithm_id: str) -> Future:
        """
        非阻塞式提交上传任务
        返回Future对象用于跟踪任务状态
        """
        async def _async_wrapper():
            async with aiohttp.ClientSession() as session:
                return await self._execute_upload(
                    session, source_dir, api_url,
                    camera_name, video_name, algorithm_id
                )

        return asyncio.run_coroutine_threadsafe(_async_wrapper(), self._loop)

    async def _execute_upload(self, session: aiohttp.ClientSession,
                            source_dir: str, api_url: str,
                            camera_name: str, video_name: str, algorithm_id: str):
        """执行实际的上传逻辑"""
        result = {"total": 0, "success": 0, "failed": []}
        try:
            api_url = self._validate_url(api_url)
            image_files = sorted(
                Path(source_dir).glob("*.jpg"),
                key=self._extract_timestamp
            )

            for batch in self._chunk_files(image_files, batch_size=10):  # 每批10个文件
                batch_result = await self._upload_batch(
                    session, batch, api_url,
                    camera_name, video_name, algorithm_id
                )
                result["total"] += len(batch)
                result["success"] += batch_result["success"]
                result["failed"].extend(batch_result["failed"])

        except Exception as e:
            print(f"上传异常: {str(e)}")
        return result

    async def _upload_batch(self, session: aiohttp.ClientSession, batch: list,
                          api_url: str, camera_name: str, video_name: str, 
                          algorithm_id: str) -> dict:
        """处理单个批次上传"""
        for attempt in range(self.max_retries):
            try:
                form = FormData()
                form.add_field("cameraName", camera_name)
                form.add_field("videoName", video_name)
                form.add_field("algorithmId", algorithm_id)

                # 批量添加文件字段
                for idx, img_path in enumerate(batch):
                    loop = asyncio.get_running_loop()
                    file_content = await loop.run_in_executor(
                        None, 
                        lambda p=img_path: p.read_bytes()
                    )
                    form.add_field(f"images[{idx}].name", img_path.name)
                    form.add_field(f"images[{idx}].time", 
                                 self._parse_timestamp(img_path).isoformat())
                    form.add_field(f"images[{idx}].file", file_content,
                                 filename=img_path.name, 
                                 content_type="image/jpeg")

                async with session.post(api_url, data=form,
                                      timeout=aiohttp.ClientTimeout(total=30)) as resp:
                    if resp.status == 200:
                        return await self._handle_success(resp, batch)
                    print(f"尝试 {attempt+1} 失败，状态码: {resp.status}")

            except (aiohttp.ClientError, asyncio.TimeoutError) as e:
                print(f"网络错误: {str(e)}")
            except Exception as e:
                print(f"处理错误: {str(e)}")

            if attempt < self.max_retries - 1:
                await asyncio.sleep(self.retry_delay)

        return {"success": 0, "failed": [p.name for p in batch]}

    async def _handle_success(self, response: aiohttp.ClientResponse, batch: list) -> dict:
        """处理成功响应"""
        data = await response.json()
        success_files = data.get("data", {}).get("success", [])
        return {
            "success": len(success_files),
            "failed": [p.name for p in batch if p.name not in success_files]
        }

    def _chunk_files(self, files: list, batch_size: int = 10):
        """将文件分批次"""
        for i in range(0, len(files), batch_size):
            yield files[i:i + batch_size]

    def _validate_url(self, url: str) -> str:
        """URL校验逻辑"""
        url = url.replace("http://http://", "http://").replace("https://https://", "https://")
        if not url.startswith(("http://", "https://")):
            url = f"http://{url}"
        return url.rstrip('/')

    def _extract_timestamp(self, path: Path) -> int:
        """提取时间戳用于排序"""
        try:
            return int(re.findall(r'\d+', path.stem)[-1])
        except:
            return 0

    def _parse_timestamp(self, path: Path) -> datetime:
        """解析时间戳"""
        try:
            parts = path.stem.split('_')
            if len(parts) >= 2:
                return datetime.strptime('_'.join(parts[-2:]), self.time_format)
        except:
            pass
        return datetime.fromtimestamp(path.stat().st_mtime)

# if __name__ == "__main__":
#     # 初始化上传服务
#     upload_service = AsyncUploadService()

#     # 非阻塞提交上传任务
#     future = upload_service.upload_images(
#         source_dir="/data/control_communication/keyuan/keyuan/problem_cross",
#         api_url="http://192.168.0.142:80/aiApi/saveEvent",
#         camera_name="keyuan",
#         video_name="keyuan",
#         algorithm_id="1"
#     )

#     # 主线程继续执行其他任务
#     print("主线程继续执行...")
#     for i in range(1, 6):
#         print(f"主线程执行其他任务 {i}/5")
#         import time
#         time.sleep(2)
#     print(future.result)
    # 可选：等待上传完成（非必须）
    # result = future.result(timeout=60)
    # print("上传结果:", result)